/**********************************************************************************
***
***    Screencasting Teaching System C++ Library
***    Copyright (C) 2011  Jiri Novak <jiri.novak@petriny.net>
***                        Wadi Jalil Maluf <wadijm@gmail.com>
***
***    This file is part of the Screencasting Teaching System C++ Library.
***
***    This library is free software; you can redistribute it and/or modify
***    it under the terms of the GNU General Public License as published by
***   the Free Software Foundation; either version 3 of the License, or
***    (at your option) any later version.
***
***    This library is distributed in the hope that it will be useful,
***    but WITHOUT ANY WARRANTY; without even the implied warranty of
***    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
***   GNU General Public License for more details.
***
***    You should have received a copy of the GNU General Public License
***    along with this library; if not, write to the Free Software
***    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
***
*********************************************************************************/
#include <iostream>
#include "clientattender.h"
#include "../common/comm/operation.h"
#include "../common/comm/protocol.h"

ClientAttender::ClientAttender(SocketTcp* socket,ClientService& serviceClient,ScreencastService &scService,std::string path):service(serviceClient),screencastService(scService), logger_(log4cxx::Logger::getLogger("server.clientattender")){
  this->closed = false;
  this->confPath=path;
  this->recordingScreencast=false;
  this->cliente=socket;
  sender=new SocketMsgSender(&queue,socket);
  this->scPersistenceService = 0;
}

ClientAttender::~ClientAttender() {
  delete cliente;
  delete sender;
}

void ClientAttender::freeResources() {
  closed = true;
  LOG4CXX_TRACE(logger_, "Closing sender and queue" );
  sender->close();
  queue.closeQueue();
  LOG4CXX_TRACE(logger_, "Waiting for sender to finish" );
  sender->join();
}

bool ClientAttender::isClosed() {
  return closed;
}

void ClientAttender::start() {
  Thread::start();
  sender->start();
}

void ClientAttender::run() {

  Operation operacion;
  while (cliente->isAvaliable()) {
      unsigned char buffer[30000];
      int cantidadLeidos = cliente->recibir(buffer, 30000);
      if (cantidadLeidos > 0) {
          LOG4CXX_TRACE(logger_, "Leidos " << cantidadLeidos);
          operacion.add(buffer, cantidadLeidos);
          while(operacion.isComplete()) {
              processRequest(operacion);
              operacion.reset();
          }
      }
  }

}

void ClientAttender::processRequest(Operation& op) {
  LOG4CXX_TRACE(logger_, "Procesando respuesta" );
  std::vector<char> response;

  switch(op.getType()){
  case Protocol::LOGOUT_REQUEST :{
    if(user!=NULL){
        user->logout();
        screencastService.logoutUser(user);
    }
  }break;
  case Protocol::LOGIN_REQUEST :{
    std::string username=protocol.getUsername(op);
    std::string password=protocol.getPassword(op);
    LOG4CXX_TRACE(logger_, "login request: "+username+"-"+password);
    user=service.login(username,password);
    if(user!=NULL){
        user->setLogged();
        screencastService.registerLoggedUser(user,&queue);
    }
    response=protocol.buildLoginMessage(user);
    queue.push(response);
  }break;
  case Protocol::FIND_SHOWS:{
    LOG4CXX_TRACE(logger_, "find shows request ");
    std::list<Course*> *userCourses=service.findCourses(user);
    std::list<Lesson*> *userLessons=service.findLessons(user);
    response= protocol.serializeShows(*userCourses,*userLessons);
    delete userCourses;
    delete userLessons;
    queue.push(response);
  }break;
  case Protocol::START_SCREENCAST_RECORDING:{
    recordingScreencast=true;
  }
  case Protocol::START_SCREENCAST :{
    LOG4CXX_TRACE(logger_, "start screencast request");
    Lesson* remoteLesson=protocol.parseLesson(op);
    currentLesson=service.startLesson(*remoteLesson);

    // Borrar lesson creada y objetos creados por protocol.parse
    screencastService.broadcastStudents(*currentLesson,op);
    if(recordingScreencast){
        scPersistenceService=new ScPersistenceService(*currentLesson,confPath);
        scPersistenceService->openForWriting();
    }
    delete remoteLesson;
  }break;
  case Protocol::CHAT_MESSAGE:{
    LOG4CXX_TRACE(logger_, "forwarding chat message");
    Lesson l;
    ChatMessage* chatMessage=protocol.parseChatMessage(op);
    l.setId(chatMessage->getLesson());
    delete chatMessage;
    screencastService.broadcast(*service.findLesson(l),op);
    if(recordingScreencast){
        std::vector<char> msgData=op.getDataBytes();
        scPersistenceService->persistChatMessage(&msgData.at(0),msgData.size());
    }
  }break;
  case Protocol::SCREENCAST_AUDIO_DATA:
  case Protocol::SCREENCAST_DATA:{
    LOG4CXX_TRACE(logger_, "forwarding screencast data");
    screencastService.broadcastStudents(*currentLesson,op);
    if(recordingScreencast){
        std::vector<char> msgData=op.getDataBytes();
        scPersistenceService->persistScreenCastData(&msgData.at(0),msgData.size());
    }
  }break;
  case Protocol::STOP_SCREENCAST_USER_REQUEST:{
    LOG4CXX_TRACE(logger_, "stopping screencast data request");
    Lesson* remoteLesson=protocol.parseLesson(op);
    Lesson * l=service.findLesson(*remoteLesson);
    l->setStudentListening(user,false);
    delete remoteLesson;
  }break;
  case Protocol::STOP_SCREENCAST:{
    LOG4CXX_TRACE(logger_, "stopping screencast data");
    screencastService.broadcast(*currentLesson,op);
    currentLesson->stop();
    recordingScreencast=false;
    if (scPersistenceService)
      delete scPersistenceService;
  }break;
  case Protocol::START_SCREENCAST_PLAYBACK:{

    LOG4CXX_TRACE(logger_, "start screencast playback");
    Lesson* remoteLesson=protocol.parseLesson(op);
    Lesson* localLesson=service.findLesson(*remoteLesson);
    if(!localLesson->isPlaying()){
        ScPersistenceService scService(*localLesson,confPath);
        if(scService.isAvailable()){
            scService.openForReading();
            scService.sendSavedScreencast(queue);
        }else{
            response=protocol.buildScreencastFailed(localLesson);
            queue.push(response);
        }
    }else{
        localLesson->setStudentListening(user,true);
    }
    delete remoteLesson;
  }
  }

}
